package fsmsim.buffer;

import fsmsim.dataStructure.Container;
import fsmsim.dataStructure.ContainerArray;
import fsmsim.dataStructure.Event;

/**
 * <p>Title: FSMSim</p>
 *
 * <p>Description: Simulatore di macchine a stati finiti.</p>
 *
 * <p>Copyright: Copyright (c) 2008</p>
 *
 * <p>Company: Bollati, Donati, Gabrielli, Peli</p>
 *
 * @author Bollati, Donati, Gabrielli, Peli
 * @version 3.0
 */

abstract public class Buffer {
    
    public static final String FIFO = "FIFO";
    public static final String LIFO = "LIFO";
    
    
    /**
     * buffer
     */

    protected Container buffer;
    
    
    /**
     * La politica di gestione del buffer
     */

    protected BufferPolicy policy;

    
    /**
     * Costruttore
     *
     * @param tipoPolitica int
     */

    public Buffer(int policyType, int dimension) {
        this.buffer = new ContainerArray(dimension);
               
        if (policyType == -1) {
            policy = new BufferPolicyIgnore();
        }
        else {
            policy = new BufferPolicyReplace(policyType);
        }
        
    }
    
    
    /**
     * Restituisce il buffer
     * @return
     */
    
    public Container getBuffer() {
        return this.buffer;
    }
    
    
    /**
     * Restituisce la politica associata al buffer
     * @return
     */
    
    public BufferPolicy getPolicy() {
        return this.policy;
    }

    
    /**
     * Aggiunge un evento nel buffer
     * @param aEvent
     */

    abstract public void addEvent(Event aEvent);

    
    /**
     * Preleva un evento dal buffer
     * @return
     */

    abstract public Event drawEvent();
    

    /**
     * Ritorna una copia del prossimo evento da prelevare dal buffer (senza
     * prelevarlo)
     * @return
     */

    abstract public Event getEvent();

    
    /**
     * Sostituisce l'evento in una posizione del buffer
     * @param aEvent
     * @param position
     */

    protected void addEvent(Event aEvent, int position) {
        this.getBuffer().addElement(aEvent, position);
    }
    
    
    /**
     * Restituisce la lunghezza del buffer
     * @return
     */

    public int size() {
        return this.getBuffer().size();
    }
    
    
    /**
     * Verifica che il buffer sia vuoto oppure che gli eventi in esso contenuti 
     * siano tutti presenti nella lista di eventi di ingresso
     * @param aContainer
     * @return
     */
    
    public boolean checkBufferEvents(Container aContainer) {
        for (int i = 0; i < size(); i++){
            if((getEvent() != null) && !(aContainer.containsElement(getEvent())))
                return false;
        }
        return true;       
    }
    
    
    /**
     * Torna true se il buffer è completamente pieno
     * @return
     */
    
    abstract public boolean isFull();

    
    /**
     * Torna true se il buffer è completamente vuoto
     * @return
     */

    abstract public boolean isEmpty();

    
    /**
     * Metodo toString
     * @return
     */

    @Override
    public String toString() {
        String bufferString;
        bufferString = "[ ";
        for (int i = 0; i < this.size(); i++) {
            bufferString += ((this.getBuffer().getElement(i) == null) ? "-" :
                             this.getBuffer().getElement(i).toString());
            bufferString += (i != this.size() - 1) ? " | " : "";
        }
        bufferString = bufferString + " ]";

        return bufferString;
    }

}
